{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/ownership/ownership.html\n",
    "- https://practice-zh.course.rs/ownership/ownership.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/ownership/ownership.md\n",
    "\n",
    "传统内存安全解决方案的问题：\n",
    "\n",
    "| 方式                    | 优点                                            | 缺点                                                         |\n",
    "| ----------------------- | ----------------------------------------------- | ------------------------------------------------------------ |\n",
    "| **GC (垃圾回收)**       | 自动管理内存，使用简单                          | • 性能开销<br>• 内存占用大<br>• Stop the World 暂停<br>• 不适合系统编程 |\n",
    "| **手动管理 (C)**        | 性能最优                                        | • 容易出错<br>• 内存泄漏<br>• 悬垂指针                       |\n",
    "| **RAII (C++)**          | • 自动资源管理<br>• 无 GC 开销                  | • 需要手动管理移动语义<br>• 可能出现悬垂引用<br>• 编译器不强制检查 |\n",
    "| **所有权系统 (Rust)** ✨ | • 无 GC<br>• **编译期**内存安全<br>• 零成本抽象 | • 学习曲线陡峭                                               |\n",
    "\n",
    "<br>\n",
    "\n",
    "`Copy` 与非 `Copy` 类型的对比\n",
    "\n",
    "| 维度              | 实现 `Copy` 的类型                                     | 未实现 `Copy` 的类型                                         | 备注                                                         |\n",
    "| ----------------- | ------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| **存储表现**      | 倾向于存储在栈上，或是指向其他地方的**只读引用**       | 往往包含堆分配或独占资源（但也可能全在栈上，比如大数组）     | *存储位置并非判断 `Copy` 的严格标准；核心是“按位复制是否安全”* |\n",
    "| **大小特征**      | 编译期已知、固定大小                                   | 可能固定也可能动态，如 `String`（固定大小头部 + 堆数据）     |                                                              |\n",
    "| **复制成本**      | 极低：简单的按位复制就能得到正确语义                   | 可能较高：复制时需要执行深拷贝或资源管理                     |                                                              |\n",
    "| **赋值/传参行为** | 自动复制值，不会意味着所有权转移                       | 默认是移动语义：赋值/传参会转移所有权                        | 调用 `.clone()` 可以显式复制                                 |\n",
    "| **典型类型**      | 整型、浮点数、布尔值、字符、不可变引用（`&T`）         | `String`、`Vec<T>`、`HashMap<K, V>`、可变引用（`&mut T`）等  | `Copy` 类型也自动实现 `Clone`                                |\n",
    "| **常见误区**      | “有 `Copy` 就一定在栈上”——实际上引用类 `Copy` 也指向堆 | “没 `Copy` 就一定在堆上”——大数组或 `struct` 里全栈也可能非 `Copy` | 关键是是否需要析构                                           |\n",
    "\n",
    "`Copy` 与 `Clone` 的核心区别\n",
    "\n",
    "| 维度         | `Copy`                                         | `Clone`                                             |\n",
    "| ------------ | ---------------------------------------------- | --------------------------------------------------- |\n",
    "| **触发方式** | 隐式：赋值、传参、返回都会执行拷贝             | 显式：需要调用 `.clone()`                           |\n",
    "| **语义**     | 按位复制（bitwise copy），无需自定义析构       | 可执行任意复制逻辑（深拷贝、堆分配等）              |\n",
    "| **代价**     | 必须非常低廉（编译器通常优化为 `memcpy`）      | 可能昂贵（取决于类型实现）                          |\n",
    "| **可选性**   | 有严格条件：必须保证按位复制后语义仍正确且安全 | 几乎所有类型都能实现，自定义逻辑完全由你决定        |\n",
    "| **适用场景** | 小型、纯值语义的数据（整型、浮点数、指针等）   | 需要有意识地复制复杂资源或拥有自定义复制策略时      |\n",
    "| **关系**     | `Copy` 是 `Clone` 的子 trait（`Copy: Clone`）  | `Clone` 可以没有 `Copy`，但有 `Copy` 必然有 `Clone` |\n",
    "\n",
    "- **`Copy` = 廉价、自动复制**：类型保证“按位复制即可”，所以“用多少次都没问题”。\n",
    "- **非 `Copy` = 所有权语义明显**：赋值/传参后原值失效，需要显式 `clone()` 才能复制。\n",
    "- **`Clone` 提供显式复制入口**：无论类型是否 `Copy`，你都可以通过 `clone()` 表达“我要多一份”。\n",
    "\n",
    "当你看到一个类型不是 `Copy`，你不能默认它能被 `clone()`；要确认该类型是否实现了 `Clone` trait。如果没有实现，就只能移动（或借用）它，而不能复制"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 所有权\n",
    "\n",
    "- https://course.rs/basic/ownership/ownership.html\n",
    "- https://practice-zh.course.rs/ownership/ownership.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/ownership/ownership.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一段不安全的代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "int* foo() {\n",
    "    int a;          // 变量a的作用域开始\n",
    "    a = 100;\n",
    "    char *c = \"xyz\";   // 变量c的作用域开始\n",
    "    return &a;\n",
    "}                   // 变量a和c的作用域结束"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 问题类型     | 变量         | 存储位置   | 问题描述                                 | 编译   | 运行   | 后果                         |\n",
    "| ------------ | ------------ | ---------- | ---------------------------------------- | ------ | ------ | ---------------------------- |\n",
    "| **悬空指针** | `a`          | 栈 (Stack) | 返回局部变量地址<br>函数结束后内存被回收 | ✅ 通过 | ❌ 错误 | 指向已释放内存<br>未定义行为 |\n",
    "| **内存泄漏** | `c` (字符串) | 常量区     | 只用一次也不释放<br>直到程序结束才回收   | ✅ 通过 | ⚠️ 浪费 | 内存无法及时释放<br>资源浪费 |\n",
    "\n",
    "- C vs Rust 对比\n",
    "\n",
    "| 特性             | C 语言         | Rust             |\n",
    "| ---------------- | -------------- | ---------------- |\n",
    "| **悬空指针检测** | ❌ 编译器不检查 | ✅ 编译期错误     |\n",
    "| **内存安全保证** | ❌ 依赖程序员   | ✅ 编译器强制     |\n",
    "| **问题发现时机** | ⚠️ 运行时       | ✅ 编译时         |\n",
    "| **性能开销**     | 无             | 无（零成本抽象） |\n",
    "| **需要 GC**      | ❌              | ❌                |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 栈(Stack)与堆(Heap)\n",
    "\n",
    "| 特性         | 栈 (Stack)                  | 堆 (Heap)                  |\n",
    "| ------------ | --------------------------- | -------------------------- |\n",
    "| **数据结构** | 后进先出 (LIFO)<br>像叠盘子 | 无组织结构<br>像餐馆找座位 |\n",
    "| **数据大小** | ✅ 必须已知且固定            | ✅ 可以未知或可变           |\n",
    "| **分配方式** | 自动压栈/出栈               | 需要请求分配内存           |\n",
    "| **访问方式** | 直接访问                    | 通过指针访问               |\n",
    "| **速度**     | ⚡ 快                        | 🐌 慢                       |\n",
    "| **管理难度** | 简单                        | 复杂                       |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### 所有权与堆栈\n",
    "\n",
    "- 当你的代码调用一个函数时，传递给函数的参数（包括可能指向堆上数据的指针和函数的局部变量）依次被压入栈中，当函数调用结束时，这些值将被从栈中按照相反的顺序依次移除。\n",
    "- 因为堆上的数据缺乏组织，因此跟踪这些数据何时分配和释放是非常重要的，否则堆上的数据将产生内存泄漏 —— 这些数据将永远无法被回收。这就是 Rust 所有权系统为我们提供的强大保障。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 所有权原则\n",
    "\n",
    "理解了堆栈，接下来看一下*关于所有权的规则*，首先请谨记以下规则：\n",
    "1. Rust 中每一个值都被一个变量所拥有，该变量被称为值的所有者\n",
    "2. 一个值同时只能被一个变量所拥有，或者说一个值只能拥有一个所有者\n",
    "3. 当所有者（变量）离开作用域范围时，这个值将被丢弃(drop)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 变量作用域"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "{                      // s 在这里无效，它尚未声明\n",
    "    let s = \"hello\";   // 从此处起，s 是有效的\n",
    "\n",
    "    // 使用 s\n",
    "}                      // 此作用域已结束，s不再有效"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 简单介绍 String 类型\n",
    "\n",
    "- [String](https://course.rs/basic/compound-type/string-slice.html) 类型通过在堆上动态分配和可变扩展，补足了编译期已知且不可变的字符串字面值，以便在运行时处理用户输入等未知大小文本，从而引出其与所有权的交互。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let s = String::from(\"hello\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world!\n"
     ]
    }
   ],
   "source": [
    "let mut s = String::from(\"hello\");\n",
    "\n",
    "s.push_str(\", world!\"); // push_str() 在字符串后追加字面值\n",
    "\n",
    "println!(\"{}\", s); // 将打印 `hello, world!`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 变量绑定背后的数据交互"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 转移所有权"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let x = 5;\n",
    "let y = x;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Rust 中，像整数这样的栈上基本类型赋值只是快速的值拷贝，不涉及所有权转移，也不会产生显著性能开销。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let s1 = String::from(\"hello\");\n",
    "let s2 = s1;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当把 `String` 赋值给另一个变量时，Rust 不会深拷贝堆数据，而是转移所有权以避免两个指针同时释放同一块内存，从而防止二次释放错误。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `s1`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `s1`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_3:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;68m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m      \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `s1` has type `String`, which does not implement the `Copy` trait",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54m1\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m           \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;100m1\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                        \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// 在所有权转移后再来使用旧的所有者，会发生什么\n",
    "\n",
    "let s1 = String::from(\"hello\");\n",
    "let s2 = s1;\n",
    "\n",
    "println!(\"{}, world!\", s1);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello, world, hello, world\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// 这段代码不会报错，因为 &str 是对程序内嵌字符串的引用，let y = x; 只复制引用本身，不涉及所有权转移。\n",
    "\n",
    "{\n",
    "    let x: &str = \"hello, world\";\n",
    "    let y = x;\n",
    "    println!(\"{}, {}\",x,y);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Clone / 显式复制入口，允许实现浅拷贝或深拷贝\n",
    "\n",
    "- 在 Rust 中只有显式调用 `clone` 才会深拷贝 `String` 的堆数据，从而保留原所有者；由于性能开销巨大，应仅在必要时使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let s1 = String::from(\"hello\");\n",
    "let s2 = s1.clone();\n",
    "\n",
    "println!(\"s1 = {}, s2 = {}\", s1, s2);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Copy / 按位复制\n",
    "\n",
    "- 浅拷贝只涉及栈上数据，性能高且常见；具备 `Copy` 特征的简单栈上类型（整数、浮点、布尔、字符以及仅含 `Copy` 成员的元组和不可变引用等）赋值时自动复制，不会触发所有权转移或需要 `clone`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "let x = 5;\n",
    "let y = x;\n",
    "\n",
    "println!(\"x = {}, y = {}\", x, y);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 函数传值与返回\n",
    "\n",
    "将值传递给函数，一样会发生 移动 或者 复制，就跟 `let` 语句一样，下面的代码展示了所有权、作用域的规则："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let s = String::from(\"hello\");  // s 进入作用域\n",
    "\n",
    "    takes_ownership(s);             // s 的值移动到函数里 ...\n",
    "                                    // ... 所以到这里不再有效\n",
    "\n",
    "    let x = 5;                      // x 进入作用域\n",
    "\n",
    "    makes_copy(x);                  // x 应该移动函数里，\n",
    "                                    // 但 i32 是 Copy 的，所以在后面可继续使用 x\n",
    "\n",
    "} // 这里, x 先移出了作用域，然后是 s。但因为 s 的值已被移走，\n",
    "  // 所以不会有特殊操作\n",
    "\n",
    "fn takes_ownership(some_string: String) { // some_string 进入作用域\n",
    "    println!(\"{}\", some_string);\n",
    "} // 这里，some_string 移出作用域并调用 `drop` 方法。占用的内存被释放\n",
    "\n",
    "fn makes_copy(some_integer: i32) { // some_integer 进入作用域\n",
    "    println!(\"{}\", some_integer);\n",
    "} // 这里，some_integer 移出作用域。不会有特殊操作\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "borrow of moved value: `s`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0382] Error:\u001b[0m borrow of moved value: `s`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_4:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m         \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m move occurs because `s` has type `String`, which does not implement the `Copy` trait",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                     \u001b[38;5;54m┬\u001b[0m\u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                     \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m value moved here",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;37m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;37m╰\u001b[0m\u001b[38;5;37m─\u001b[0m help: consider cloning the value if the performance cost is acceptable: `.clone()`",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                      \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m value borrowed here after move",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/vxWzh98ch\n",
    "fn main() {\n",
    "    let s = String::from(\"hello\");  // s 进入作用域\n",
    "\n",
    "    takes_ownership(s);             // s 的值移动到函数里 ...\n",
    "                                    // ... 所以到这里不再有效\n",
    "    println!(\"在move进函数后继续使用s: {}\",s);\n",
    "}\n",
    "\n",
    "fn takes_ownership(some_string: String) { // some_string 进入作用域\n",
    "    println!(\"{}\", some_string);\n",
    "} // 这里，some_string 移出作用域并调用 `drop` 方法。占用的内存被释放\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样的，函数返回值也有所有权，例如:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let s1 = gives_ownership();         // gives_ownership 将返回值\n",
    "                                        // 移给 s1\n",
    "\n",
    "    let s2 = String::from(\"hello\");     // s2 进入作用域\n",
    "\n",
    "    let s3 = takes_and_gives_back(s2);  // s2 被移动到\n",
    "                                        // takes_and_gives_back 中,\n",
    "                                        // 它也将返回值移给 s3\n",
    "} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域，但已被移走，\n",
    "  // 所以什么也不会发生。s1 移出作用域并被丢弃\n",
    "\n",
    "fn gives_ownership() -> String {             // gives_ownership 将返回值移动给\n",
    "                                             // 调用它的函数\n",
    "\n",
    "    let some_string = String::from(\"hello\"); // some_string 进入作用域.\n",
    "\n",
    "    some_string                              // 返回 some_string 并移出给调用的函数\n",
    "}\n",
    "\n",
    "// takes_and_gives_back 将传入字符串并返回该值\n",
    "fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域\n",
    "\n",
    "    a_string  // 返回 a_string 并移出给调用的函数\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 引用与借用 / Reference and Borrowing\n",
    "\n",
    "- https://course.rs/basic/ownership/borrowing.html\n",
    "- https://practice-zh.course.rs/ownership/borrowing.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/ownership/borrowing.md\n",
    "\n",
    "上节中提到，如果仅仅支持通过转移所有权的方式获取一个值，那会让程序变得复杂。 Rust 能否像其它编程语言一样，使用某个变量的指针或者引用呢？答案是可以。\n",
    "\n",
    "Rust 通过 `借用(Borrowing)` 这个概念来达成上述的目的，**获取变量的引用，称之为借用(borrowing)**。正如现实生活中，如果一个人拥有某样东西，你可以从他那里借来，当使用完毕后，也必须要物归原主。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 引用与解引用\n",
    "\n",
    "常规引用是一个指针类型，指向了对象存储的内存地址"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn main() {\n",
    "    let x = 5;\n",
    "    let y = &x;\n",
    "\n",
    "    assert_eq!(5, x);\n",
    "    assert_eq!(5, *y); // 解引用\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "can't compare `{integer}` with `&{integer}`",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0277] Error:\u001b[0m can't compare `{integer}` with `&{integer}`",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_7:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mq\u001b[0m\u001b[38;5;54m!\u001b[0m\u001b[38;5;54m(\u001b[0m\u001b[38;5;54m5\u001b[0m\u001b[38;5;54m,\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54my\u001b[0m\u001b[38;5;54m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m no implementation for `{integer} == &{integer}`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let x = 5;\n",
    "    let y = &x;\n",
    "\n",
    "    assert_eq!(5, x);\n",
    "    assert_eq!(5, y);\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 不可变引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The length of 'hello' is 5.\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let s1 = String::from(\"hello\");\n",
    "\n",
    "    let len = calculate_length(&s1); // 创建了一个指向 s1 的引用，但是并不拥有它\n",
    "\n",
    "    println!(\"The length of '{}' is {}.\", s1, len);\n",
    "}\n",
    "\n",
    "fn calculate_length(s: &String) -> usize { // & 符号即是引用，它们允许你使用值，但是不获取所有权\n",
    "    s.len()\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `*some_string` as mutable, as it is behind a `&` reference",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0596] Error:\u001b[0m cannot borrow `*some_string` as mutable, as it is behind a `&` reference",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_11:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m:\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                         \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider changing this to be a mutable reference: `mut `",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mg\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mw\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m     \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m \u001b[38;5;115mNote\u001b[0m: You can change an existing variable to mutable like: `let mut x = x;`",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let s = String::from(\"hello\");\n",
    "\n",
    "    change(&s); // 正如变量默认不可变一样，引用指向的值默认也是不可变的\n",
    "}\n",
    "\n",
    "fn change(some_string: &String) {\n",
    "    some_string.push_str(\", world\");\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 可变引用 / &mut"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s: hello, world\n"
     ]
    }
   ],
   "source": [
    "fn main() {\n",
    "    let mut s = String::from(\"hello\");\n",
    "\n",
    "    change(&mut s);\n",
    "\n",
    "    println!(\"s: {}\", s);\n",
    "}\n",
    "\n",
    "fn change(some_string: &mut String) {\n",
    "    some_string.push_str(\", world\");\n",
    "}\n",
    "\n",
    "main();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 可变引用(可变借用)同时只能存在一个\n",
    "\n",
    "- 在同一作用域内只能存在一个对特定数据的可变引用，这是 Rust 借用检查器在编译期防止数据竞争的关键规则。想要再次创建可变引用，可利用额外的作用域（如包裹在大括号中）让先前的借用提前离开作用域，从而安全地获得新的可变引用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "The variable `r1` contains a reference with a non-static lifetime so\ncan't be persisted. You can prevent this error by making sure that the\nvariable goes out of scope - i.e. wrapping the code in {}.",
     "output_type": "error",
     "traceback": [
      "\u001b[31mError:\u001b[0m The variable `r1` contains a reference with a non-static lifetime so",
      "can't be persisted. You can prevent this error by making sure that the",
      "variable goes out of scope - i.e. wrapping the code in {}."
     ]
    },
    {
     "ename": "Error",
     "evalue": "cannot borrow `s` as mutable more than once at a time",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0499] Error:\u001b[0m cannot borrow `s` as mutable more than once at a time",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_13:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m first mutable borrow occurs here",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mu\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;100m \u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m          \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m second mutable borrow occurs here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "let mut s = String::from(\"hello\");\n",
    "\n",
    "let r1 = &mut s;\n",
    "let r2 = &mut s;\n",
    "\n",
    "println!(\"{}, {}\", r1, r2);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{\n",
    "  let mut s = String::from(\"hello\");\n",
    "\n",
    "  {\n",
    "      let r1 = &mut s;\n",
    "\n",
    "  } // r1 在这里离开了作用域，所以我们完全可以创建一个新的引用\n",
    "\n",
    "  let r2 = &mut s;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 可变引用与不可变引用(可变借用与不可变引用)不能同时存在\n",
    "\n",
    "- Rust 通过限制同一数据只能同时存在多个不可变引用或唯一的可变引用，并在最后使用点结束借用以提升灵活性，从而在编译期杜绝数据竞争。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "cannot borrow `s` as mutable because it is also borrowed as immutable",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0502] Error:\u001b[0m cannot borrow `s` as mutable because it is also borrowed as immutable",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_16:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100m&\u001b[0m\u001b[38;5;100ms\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m             \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m immutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m6 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54mu\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54m \u001b[0m\u001b[38;5;54ms\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m            \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m               \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m mutable borrow occurs here",
      " \u001b[38;5;240m  │\u001b[0m ",
      " \u001b[38;5;246m8 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;68mr\u001b[0m\u001b[38;5;68m1\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                              \u001b[38;5;68m─\u001b[0m\u001b[38;5;68m┬\u001b[0m  ",
      " \u001b[38;5;240m  │\u001b[0m                               \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m immutable borrow later used here",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "{\n",
    "  let mut s = String::from(\"hello\");\n",
    "\n",
    "  let r1 = &s; // 没问题\n",
    "  let r2 = &s; // 没问题\n",
    "  let r3 = &mut s; // 大问题\n",
    "\n",
    "  println!(\"{}, {}, and {}\", r1, r2, r3);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Rust 1.31 之前，借用的生命周期与变量作用域一致，导致同时存在不可变引用与后续可变引用会报错；自引入**非词法生命周期（NLL）**后，借用在最后一次使用后即结束，使得先使用不可变引用、再创建可变引用的模式得以安全编译通过。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello and hello\n",
      "hello\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn main() {\n",
    "   let mut s = String::from(\"hello\");\n",
    "\n",
    "    let r1 = &s;\n",
    "    let r2 = &s;\n",
    "    println!(\"{} and {}\", r1, r2);\n",
    "    // 新编译器中，r1,r2作用域在这里结束\n",
    "\n",
    "    let r3 = &mut s;\n",
    "    println!(\"{}\", r3);\n",
    "} // 老编译器中，r1、r2、r3作用域在这里结束\n",
    "  // 新编译器中，r3作用域在这里结束\n",
    "\n",
    "main() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### NLL\n",
    "\n",
    "- 对于这种编译器优化行为，Rust 专门起了一个名字 —— Non-Lexical Lifetimes(NLL)，专门用于找到某个引用在作用域(`}`)结束前就不再被使用的代码位置。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 悬垂引用(Dangling References)\n",
    "\n",
    "悬垂引用是指向已释放数据的指针，Rust 借用检查器会在编译期阻止这一情况：如果你试图返回对局部变量的引用（如 `&s`），编译器会报错，因为借用在返回时已失去来源；要将数据安全地返回给调用者，应直接转移所有权，例如让函数返回 `String`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "missing lifetime specifier",
     "output_type": "error",
     "traceback": [
      "\u001b[31m[E0106] Error:\u001b[0m missing lifetime specifier",
      "   \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0m command_18:1:1 \u001b[38;5;246m]\u001b[0m",
      "   \u001b[38;5;246m│\u001b[0m",
      " \u001b[38;5;246m7 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m-\u001b[0m\u001b[38;5;249m>\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54m&\u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m{\u001b[0m",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;54m┬\u001b[0m\u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected named lifetime parameter",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;68m│\u001b[0m\u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                  \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: instead, you are more likely to want to return an owned value: ``",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m│\u001b[0m ",
      " \u001b[38;5;240m  │\u001b[0m                   \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`: `'static `",
      "\u001b[38;5;246m───╯\u001b[0m"
     ]
    }
   ],
   "source": [
    "// https://godbolt.org/z/b4YoxqfnM\n",
    "{\n",
    "  fn main() {\n",
    "      let reference_to_nothing = dangle();\n",
    "  }\n",
    "\n",
    "  fn dangle() -> &String {\n",
    "      let s = String::from(\"hello\");\n",
    "\n",
    "      &s\n",
    "  }\n",
    "\n",
    "  main();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "错误信息引用了一个我们还未介绍的功能：[生命周期(lifetimes)](https://course.rs/basic/lifetime.html)。\n",
    "- ` this function's return type contains a borrowed value, but there is no value for it to be borrowed from`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn dangle() -> &String { // dangle 返回一个字符串的引用\n",
    "\n",
    "    let s = String::from(\"hello\"); // s 是一个新字符串\n",
    "\n",
    "    &s // 返回字符串 s 的引用\n",
    "} // 这里 s 离开作用域并被丢弃。其内存被释放。\n",
    "  // 危险！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 解决方法是直接返回 String\n",
    "fn no_dangle() -> String {\n",
    "    let s = String::from(\"hello\");\n",
    "\n",
    "    s\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
